/*
* Copyright (c) 2007 by Kirill Kolodyazhniy.
* See the file "license.terms" for information on usage and redistribution.
*/

#include "light.h"

namespace Engine
{
	using namespace std;

	/**********************************************************************************************************/
	Light* LightFactory::CreateInstance( const std::string& name )
	{
		return new Light(name);
	}
	/**********************************************************************************************************/
	Light::Light(const std::string& name)
		:MovableObject(name)
		,m_lightType(LT_POINT)
		,m_diffuse(Color::White)
		,m_specular(Color::Black)
		,m_direction(Vector3<REAL>::UNIT_Z)
		,m_spotOuter(40.0)
		,m_spotInner(30.0)
		,m_spotFalloff(1.0)
		,m_range(100000)
		,m_attenuationConst(1.0)
		,m_attenuationLinear(0.0)
		,m_attenuationQuad(0.0)
		,m_derivedTransformDirty(false)
	{
	}
	/**********************************************************************************************************/
    Light::~Light()
	{
	}
	/**********************************************************************************************************/
    void Light::SetType(LightTypes type)
	{
		 m_lightType = type;
	}
	/**********************************************************************************************************/
	Light::LightTypes Light::GetType(void) const
	{
		return m_lightType;
	}
	/**********************************************************************************************************/
    void Light::SetDiffuseColor(const Color& color)
	{
		m_diffuse = color;
	}
	/**********************************************************************************************************/
    const Color& Light::GetDiffuseColor(void) const
	{
		return m_diffuse;
	}
	/**********************************************************************************************************/
    void Light::SetSpecularColour(const Color& color)
	{
		m_specular = color;
	}
	/**********************************************************************************************************/
    const Color& Light::GetSpecularColour(void) const
	{
		return m_specular;
	}
	/**********************************************************************************************************/
    void Light::SetAttenuation(REAL range, REAL constant, REAL linear, REAL quadratic)
	{
		m_range = range;
        m_attenuationConst = constant;
        m_attenuationLinear = linear;
        m_attenuationQuad = quadratic;
	}
	/**********************************************************************************************************/
    REAL Light::GetAttenuationRange(void) const
	{
		return m_range;
	}
	/**********************************************************************************************************/
    REAL Light::GetAttenuationConstant(void) const
	{
		return m_attenuationConst;
	}
	/**********************************************************************************************************/
    REAL Light::GetAttenuationLinear(void) const
	{
		return m_attenuationLinear;
	}
	/**********************************************************************************************************/
    REAL Light::GetAttenuationQuadric(void) const
	{
		return m_attenuationQuad;
	}
	/**********************************************************************************************************/
	const Vector3<REAL> Light::GetPosition(void) const
	{
		SceneNode* pnode = GetParentNode();
		Vector3<REAL> pos;
		if(pnode)
		{
			const Matrix4<REAL>& ntrans = pnode->GetDerivedTransform();
			pos = Vector3<REAL>(ntrans[0][3],ntrans[1][3],ntrans[2][3]);
		}
		return pos;
	}
	/**********************************************************************************************************/
    void Light::SetDirection(const Vector3<REAL>& vec)
	{
		m_direction = vec;
        m_derivedTransformDirty = true;
	}
	/**********************************************************************************************************/
    const Vector3<REAL>& Light::GetDirection(void) const
	{
		return m_direction;
	}
	/**********************************************************************************************************/
    void Light::SetSpotlightRange(REAL innerAngle, REAL outerAngle, REAL falloff)
	{
		if (m_lightType != LT_SPOTLIGHT)
			throw std::logic_error("SetSpotlightRange is only valid for spotlights.");

        m_spotInner =innerAngle;
        m_spotOuter = outerAngle;
        m_spotFalloff = falloff;
	}
	/**********************************************************************************************************/
    REAL Light::GetSpotlightInnerAngle(void) const
	{
		return m_spotInner;
	}
	/**********************************************************************************************************/
    REAL Light::GetSpotlightOuterAngle(void) const
	{
		return m_spotOuter;
	}
	/**********************************************************************************************************/
    REAL Light::GetSpotlightFalloff(void) const
	{
		return m_spotFalloff;
	}
	/**********************************************************************************************************/
    const AABB& Light::GetBoundingBox(void) const
	{
		// Null, lights are not visible
        static AABB box;
        return box;
	}
	/**********************************************************************************************************/
    void Light::UpdateRenderQueue(RenderQueue*, RenderQueue* , const std::vector<LightPtr>& )
	{
		// Do nothing
	}
	/**********************************************************************************************************/
	void Light::Accept(MovableObjectVisitor* visitor)
	{
		visitor->Visit(this);
	}
	/**********************************************************************************************************/
}
